

@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
        throws AuthenticationException, IOException, ServletException {

        OAuth2AccessToken accessToken;
        try {
        // 获取当前token，需要注意一点这个虽然用到restTemplate，但实际上这里并没有发起远程调度，这里restTemplate是OAuth2RestTemplate的实例
        // 一路点进去你会发现他只是从上下文获取到accessToken
        accessToken = restTemplate.getAccessToken();
        } catch (OAuth2Exception e) {
        BadCredentialsException bad = new BadCredentialsException("Could not obtain access token", e);
        publish(new OAuth2AuthenticationFailureEvent(bad));
        throw bad;
        }
        try {
// 这步是校验token的关键，这里tokenServices是ResourceServerTokenServices实例，这里做怎么样的操作取决是注入的ResourceServerTokenServices

// 默认情况下ResourceServerTokenServices的实例DefaultTokenServices

// 认证中心默认的就是DefaultTokenServices，这个类做的就是从OAuth2AccessToken accessToken = tokenStore.readAccessToken(accessTokenValue)

// 我们配置中心配置的tokenStore的是RedisTokenStore，所以实际上她做的就是从redis中读取出accessToken相关信息

<!-- 分割线 --->

        // 上面说的DefaultTokenServices是认证中心token的处理，资源服务下：

        // 如果配置文件中配置的user-info-uri则ResourceServerTokenServices注入的实例将是UserInfoTokenServices的实例

        // 如果配置token-info-uri则ResourceServerTokenServices注入的实例将是RemoteTokenServices

        // 如果两者都配置了，优先UserInfoTokenServices

        // UserInfoTokenServices和RemoteTokenServices做的事都是远程调度认证中心相应的接口完成token的校验

        // 两者主要区别在于RemoteTokenServices需要配置clientId和clientSecret

        // RemoteTokenServices中有这么一句话：Null Client ID or Client Secret detected. Endpoint that requires authentication will reject request with 401 error.

        // 具体请查看RemoteTokenServices和UserInfoTokenServices

        OAuth2Authentication result = tokenServices.loadAuthentication(accessToken.getValue());
        if (authenticationDetailsSource!=null) {
        request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, accessToken.getValue());
        request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_TYPE, accessToken.getTokenType());
        result.setDetails(authenticationDetailsSource.buildDetails(request));
        }
        publish(new AuthenticationSuccessEvent(result));
        return result;
        }
        catch (InvalidTokenException e) {
        BadCredentialsException bad = new BadCredentialsException("Could not obtain user details from token", e);
        publish(new OAuth2AuthenticationFailureEvent(bad));
        throw bad;
        }

        }